# coding:utf-8
import os
import sys
project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), "../"))
if project_root not in sys.path:
    sys.path.append(project_root)
import requests
import json
import streamlit as st
from transformers import AutoTokenizer, TextIteratorStreamer, TextStreamer, AutoProcessor, WhisperProcessor
from config.config import Config
from threading import Thread
from datetime import datetime
import pytz
# 使用API生成文本
def generate_response_with_api(real_prompt, config: Config, current_time: str):
    """
    使用API生成响应文本
    """
    # API URL 和请求头
    url = "https://api.siliconflow.cn/v1/chat/completions"
    headers = {
        "Authorization": f"Bearer {config.api_token}",  # 从配置中获取 API 密钥
        "Content-Type": "application/json"
    }

    # 构建请求的 payload
    payload = {
        "model": "Qwen/Qwen2.5-14B-Instruct",  # 使用你指定的模型
        "messages": [
            {"role": "system", "content": f"当前时间为{current_time}。"},
            {"role": "user", "content": real_prompt}
        ],
        "stream": True,  # 启用流式生成
        "max_tokens": config.max_new_tokens,  # 最大 token 数
        "temperature": 0.7,  # 温度
        "top_p": 0.7,  # top_p
        "top_k": 50,  # top_k
        "frequency_penalty": 0.5,  # 频率惩罚
        "n": 1,  # 生成的数量
        "response_format": {"type": "text"},  # 响应格式
        "stop": ["null"],  # 停止符
        "tools": []  # 可选工具字段，根据需要设置
    }

    # 发起请求
    response = requests.post(url, json=payload, headers=headers, stream=True)

    if response.status_code == 200:
        response_text = ""
        # 逐步读取流式返回的数据
        for chunk in response.iter_lines():
            if chunk:
                chunk_data = chunk.decode("utf-8")
                try:
                    # 打印出原始的返回数据以便调试
                    # print("收到的原始数据：", chunk_data)

                    # 去除 'data:' 前缀
                    if chunk_data.startswith("data: "):
                        chunk_data = chunk_data[6:]  # 去掉 'data: ' 部分

                    if chunk_data.strip() == "[DONE]":
                        break

                    # 解析 JSON 数据
                    chunk_json = json.loads(chunk_data)

                    # 提取生成的文本
                    content = chunk_json.get("choices", [{}])[0].get("delta", {}).get("content", "")
                    if content:
                        response_text += content
                        yield content  # 返回逐步生成的文本

                        # 在每次输出时生成 0.5 到 1 秒之间的随机延迟
                        # time.sleep(random.uniform(0.2, 0.5))

                except json.JSONDecodeError as e:
                    print(f"JSON解析错误: {e}")
                    # print(f"JSON解析错误: {e}, 返回的数据是: {chunk_data}")
                except Exception as e:
                    print(f"其他错误: {e}")
    else:
        raise Exception(f"API 请求失败，状态码: {response.status_code}, 错误信息: {response.text}")


# 使用本地模型生成文本
def generate_response_with_local_model(real_prompt, config: Config, current_time: str):
    """
    使用本地模型生成响应文本
    """
    model, tokenizer = config.chat_model

    text = tokenizer.apply_chat_template([
        {"role": "system", "content": f"当前时间为{current_time}。"},
        {"role": "user", "content": real_prompt}
    ], tokenize=False, add_generation_prompt=True)

    model_inputs = tokenizer([text], return_tensors="pt").to("xpu")

    streamer = TextIteratorStreamer(tokenizer, skip_prompt=True, skip_special_tokens=True)
    generation_kwargs = dict(inputs=model_inputs.input_ids, max_new_tokens=config.max_new_tokens, streamer=streamer)
    thread = Thread(target=model.generate, kwargs=generation_kwargs)
    thread.start()

    return streamer


def get_current_time():
    """获取当前时间，格式为：YYYY年MM月DD日，HH时MM分"""
    current_time = datetime.now(pytz.timezone('Asia/Shanghai'))
    return current_time.strftime("%Y年%m月%d日，%H时%M分")


# 文本生成函数
def generate_response(real_prompt, config: Config, mode: str):
    """
    根据配置使用API或本地模型生成响应文本
    """
    current_time = get_current_time()
    config.set_mode(mode)
    # 如果启用了API开关，则使用API生成文本
    if config.use_chat_api:
        return generate_response_with_api(real_prompt, config, current_time)
    else:
        return generate_response_with_local_model(real_prompt, config, current_time)


def chat(config: Config, chat_destination, chat_departure, chat_days, chat_style, chat_budget, chat_people, chat_other,
         current_weather, mode, scene_list):

    chat_scene = '、'.join(scene_list)
    """
    生成旅行计划表的聊天功能
    """
    prompt_template = """你现在是一位专业的旅行规划师，你的责任是根据旅行出发地、目的地、目的地天气情况、天数、行程风格（紧凑、适中、休闲）、预算、随行人数，帮助给定的旅游景点去规划行程并生成详细的旅行计划表。
    请你以表格的方式呈现结果。旅行计划表的表头请包含**日期**、**地点**、**行程计划**、**交通方式**、**餐饮安排**、**住宿安排**、**费用估算**、**备注**。 

**示例：**

| 日期 | 地点 | 行程计划 | 交通方式 | 餐饮安排 | 住宿安排 | 费用估算 | 备注 |
|------|------|----------|----------|----------|----------|----------|------|
| Day1 | 城市A | 上午：参观博物馆, 下午：游览公园 | 步行, 地铁 | 本地特色餐厅 | 酒店 | ￥500 | 天气晴 |
| Day2 | 城市B | 上午：购物, 下午：休息 | 出租车 | 快餐 | 民宿 | ￥400 | 注意防晒 |

表格内容根据以下旅行信息填写：
旅游出发地：{}，旅游目的地：{} ，目的地天气：{} ，天数：{}天 ，行程风格：{} ，预算：{}，随行人数：{}, 特殊偏好、要求：{}

1. 日期请以DayN为格式如Day1，明确标识每天的行程。
2. 地点需要呈现当天所在城市，请根据日期、考虑地点的地理位置远近，严格且合理制定地点，确保行程顺畅。
3. 行程计划需包含位置、时间、活动，其中位置需要根据地理位置的远近进行排序。位置的数量可以根据行程风格灵活调整，如休闲则位置数量较少、紧凑则位置数量较多。时间需要按照上午、中午、晚上制定，并给出每一个位置所停留的时间（如上午10点-中午12点）。活动需要准确描述在位置发生的对应活动（如参观博物馆、游览公园、吃饭等），并需根据位置停留时间合理安排活动类型。
4. 交通方式需根据地点、行程计划中的每个位置的地理距离合理选择，如步行、地铁、出租车、火车、飞机等不同的交通方式，并尽可能详细说明。
5. 餐饮安排需包含每餐的推荐餐厅、类型（如本地特色、快餐等）、预算范围，就近选择。
6. 住宿安排需包含每晚的推荐酒店或住宿类型（如酒店、民宿等）、地址、预估费用，就近选择。
7. 费用估算需包含每天的预估总费用，并注明各项费用的细分（如交通费、餐饮费、门票费等）。
8. 备注中需要包括对应行程计划需要考虑到的注意事项，保持多样性，涉及饮食、文化、天气、语言等方面的提醒。
9. 请特别考虑随行人数的信息，确保行程和住宿安排能满足所有随行人员的需求。
10.旅游总体费用不能超过预算。

确定要去的景点有：{}
请严格按照以上表格格式生成,请确保内容全在markdown表格里，不要输出无关信息！
"""
    final_query = prompt_template.format(chat_departure, chat_destination, current_weather, chat_days, chat_style,
                                         chat_budget, chat_people, chat_other,chat_scene)
    print(final_query)

    # 收集响应的所有部分并逐步输出到文本框
    response = ""
    placeholder = st.empty()  # 创建一个占位符

    streamer = generate_response(final_query, config, mode)

    for i, chunk_text in enumerate(streamer):
        response += chunk_text
        # 逐步更新文本框内容，提供唯一的 key
        with placeholder.container():
            st.text_area("旅行计划表", value=response, height=400, key=f"response_text_{i}")

    placeholder.empty()  # 这会清空占位符区域，移除文本框
    return response


